<?php

class CError extends Exception {
	
	function __construct($error,$code) {
		//parent::__construct($error,$code);
	}
	
	/**The user function needs to accept two parameters: the error code, and a
 	* string describing the error. Then there are three optional parameters 
 	* that may be supplied: the filename in which the error occurred, the
 	* line number in which the error occurred, and the context in which the
 	* error occurred (an array that points to the active symbol table at the
 	* point the error occurred). The function can be shown as:**/
	
	/**
	 * 发生错误时触发该方法，显示追踪错误信息，并根据用户配置文件设置记录错误日志
	 * @param int $code 错误编码(也可以说是类型，比如警告，错误等)
	 * @param string $error 错误提示
	 * @param string $file 错误发生的文件
	 * @param int $line 错误发生的行数
	 */
	public static function handler($code, $error, $file=null,$line=null)
	{
		//错误编码不在当前错误报告等级范围内,则不报告/记录错误
		if (($code & error_reporting()) != $code)
		{
			return ;
		} 
		//var_dump(error_reporting());exit;
		//throw new ErrorException($error, $code, 0, $file, $line);

		$err = new ErrorException($error, $code, 0, $file, $line);
		
		/*$type    = get_class($err);
		$code    = $err->getCode();
		$message = $err->getMessage();
		$file    = $err->getFile();
		$line    = $err->getLine();*/
		$trace = $err->getTrace(); //获取追踪错误
			
		$msgStr = ""; //保存错误追踪组成的完整字符串
		$errorNo = ""; //错误类型编码，如警告，错误等
		$errorType = ""; //错误类型
		$errorMsg = ""; //错误提示
		$errorLine = "" ;//代码错误行号
		$errorFile = "" ; //错误文件
		$hasErrorMsg = false;
		
		$environment = Config::get("environment","development");
		
		$wrap = "";
		
		if($environment=="development")
		{
			$wrap = "<br />";
		}
		else
		{
			$wrap = PHP_EOL;
		}
		
		foreach($trace as $item)
		{
			$msgStr .= "";
			
			if(isset($item["args"]) && count($item["args"])>=4 && !$hasErrorMsg)
			{
				$hasErrorMsg = true;
				$errorNo = $item["args"][0];//错误等级
				$errorMsg = $item["args"][1];
				$errorFile = $item["args"][2];
				$errorLine = $item["args"][3];
				$errorType = self::getErrorType($errorNo);
				
				$msgStr .= $errorType.":".$errorMsg.$wrap.$errorFile."&nbsp".$errorLine."行".$wrap;
			}
			else
			{
				if(isset($item["file"]) && isset($item["line"]))
				{
					$errorFile = $item["file"];
					$errorLine = $item["line"];
					$msgStr .= $errorFile."&nbsp;".$errorLine."行".$wrap;
				}
			}
		}
		
		if($environment=="development") //开发环境直接输出错误
		{
			echo $msgStr;
			
			if($errorType!="Warning" && $errorType!="Notice")
			{
				exit;
			}
		}
		else {
			self::writeErrorToLog($msgStr);
		}
		
		return true;
	}
	
	public static function shutdown($param="")
	{
		
		//最后一次错误信息
		$error = error_get_last();

		if($error)
		{
			ob_clean();
			self::handler($error["type"],$error["message"], $error["file"], $error["line"]);
		}
		echo $param;
		//echo "shutdown";
		exit;
	}
	
	private static function writeErrorToLog($msgStr)
	{
		$errorConfig = Config::get("error",array());
		
		$errorConfigDefault = array(
			"writeToLog"=>true, //是否记录错误信息到日志文件
			"logDir"=>"log", //日志文件目录
			"logFileName"=>"error_log.txt", //日志文件名
			"errorUrl"=>"" //发生错误时跳转到url,为空则不跳转
		);
		
		$errorConfig = array_merge($errorConfigDefault,$errorConfig);
		
		if($errorConfig["writeToLog"])
		{
			CLog::write($msgStr,$errorConfig["logDir"],$errorConfig["logFileName"]);
		}

		if($errorConfig["errorUrl"])
		{
			header("location:".$errorConfig["errorUrl"]);
			exit;
		}
	}
	
	private static function getErrorType($errorNo)
	{
		$errorType = "";
		
		switch($errorNo)
		{
			case E_ERROR:
				$errorType = "Error";
				break;
			case E_RECOVERABLE_ERROR:
				$errorType = "Error";
				break;
			case E_WARNING:
				$errorType = "Warning";
				break;
			case E_PARSE:
				$errorType = "Parse";
				break;
			case E_NOTICE:
				$errorType = "Notice";
				break;
			case E_STRICT:
				$errorType = "Strict";
				break;
			case E_CORE_ERROR:
				$errorType = "Code Error";
				break;
			case E_CORE_WARNING:
				$errorType = "Code Warning";
				break;
			case E_COMPILE_ERROR:
				$errorType = "Compile Error";
				break;
			case E_COMPILE_WARNING:
				$errorType = "Compile Warning";
				break;
			case E_USER_ERROR:
				$errorType = "User Error";
				break;
			case E_USER_WARNING:
				$errorType = "User Warning";
				break;
			case E_USER_NOTICE:
				$errorType = "User Notice";
				break;
			default:
				$errorType = "Error";
				break;
		}
		
		return $errorType;
	}
}

?>